/*
 * @(#)Grep.java	1.3 01/12/13
 * Search a list of files for lines that match a given regular-expression
 * pattern.  Demonstrates NIO mapped byte buffers, charsets, and regular
 * expressions.
 *
 * Copyright 2001-2002 Sun Microsystems, Inc. All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or 
 * without modification, are permitted provided that the following 
 * conditions are met:
 * 
 * -Redistributions of source code must retain the above copyright  
 * notice, this  list of conditions and the following disclaimer.
 * 
 * -Redistribution in binary form must reproduct the above copyright 
 * notice, this list of conditions and the following disclaimer in 
 * the documentation and/or other materials provided with the 
 * distribution.
 * 
 * Neither the name of Sun Microsystems, Inc. or the names of 
 * contributors may be used to endorse or promote products derived 
 * from this software without specific prior written permission.
 * 
 * This software is provided "AS IS," without a warranty of any 
 * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND 
 * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY 
 * EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY 
 * DAMAGES OR LIABILITIES  SUFFERED BY LICENSEE AS A RESULT OF  OR 
 * RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE SOFTWARE OR 
 * ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE 
 * FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, 
 * SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER 
 * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF 
 * THE USE OF OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN 
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 * 
 * You acknowledge that Software is not designed, licensed or 
 * intended for use in the design, construction, operation or 
 * maintenance of any nuclear facility. 
 */
package com.filesearcher;

import java.io.*;
import java.text.DecimalFormat;
import java.util.regex.*;

public class Grep {

	// Charset and decoder for ISO-8859-15
	//private static Charset charset = Charset.forName("ISO-8859-15");
	//private static CharsetDecoder decoder = charset.newDecoder();

	// Pattern used to parse lines
	//private static Pattern linePattern = Pattern.compile(".*\r?\n");

	// The input pattern that we're looking for
	private static Pattern pattern;

	// Do we want to display line numbers?
	public boolean displayLineNumbers = false;

	// Do we want to save the results to a file?
	public boolean saveResults = false;
	public File saveFileName;
	public boolean excludeWords = false;
	public boolean ignoreCase = false;
	public int maxResultLines = 10000;
	private BufferedWriter out;
	
	public int numOfResults = 0;

	public Grep(boolean saveRes, File saveFile, boolean exclude, boolean showLineNums, boolean ignore, int maxResLines)
	{
		saveResults = saveRes;
		saveFileName = saveFile;
		excludeWords = exclude;
		ignoreCase = ignore;
		maxResultLines = maxResLines;
		displayLineNumbers = showLineNums;
	}
	
	// Compile the pattern from the command line
	private boolean compile(String pat) {
		try 
		{
			if ( ignoreCase )				
				pattern = Pattern.compile( pat.toLowerCase() );
			else
				pattern = Pattern.compile( pat );
		} 
		catch (PatternSyntaxException x) 
		{
			/*
			System.err.println(x.getMessage());
			System.exit(1); */
			//lets return false to indicate the the compile failed
			return false;
		}
		
		return true;
	}

	// Search for occurrences of the input pattern in the given file
	//
	private StringBuffer grep(File f) throws IOException 
	{
		StringBuffer results = new StringBuffer();
		
		BufferedReader br = new BufferedReader(new FileReader(f));
		boolean matched = false;
		String line;
		Matcher pm = null;			// Pattern matcher
		int lines = 0;
		numOfResults = 0;
		
		int maxLinesLen = Integer.toString(maxResultLines).length();
		String formatString = "";
		
		for (int i=1; i<=maxLinesLen; i++)
		{
			formatString = formatString + "0";
		}
		
		DecimalFormat linesFormat = new DecimalFormat(formatString);
		
		if ( saveResults && saveFileName != null )
			out = new BufferedWriter(new FileWriter(saveFileName, false));
		
		while ( (line = br.readLine()) != null ) 
		{
			if ( Runtime.getRuntime().freeMemory() < 5000 )
				break;
			
			if ( ignoreCase )				
				line.toLowerCase();
			
			matched = false;
			lines++;
			CharSequence cs = line; 	// The current line
			
			if (pm == null)
				pm = pattern.matcher(cs);
			else
				pm.reset(cs);
			
			boolean found = pm.find();
			
			if (found && excludeWords == false)
				matched = true;
			else if ( found == false && excludeWords == true )
				matched = true;
			
			if ( matched )
			{
				numOfResults++;
				
				try
				{
					if ( numOfResults > 1)
						results.append( "\n" );
		
					if ( displayLineNumbers )					
						results.append(linesFormat.format(lines) + "::" + cs);
					else
						results.append(cs.toString());
					
					if ( saveResults && out != null )
					{
						out.append( cs );
						
						if ( numOfResults < maxResultLines )
							out.append( "\n" );
						
						out.flush();
					}
				}
				catch ( OutOfMemoryError oom )
				{
					Runtime.getRuntime().gc();
					break;
				}
			}
			
			if ( numOfResults >= maxResultLines )
				break;				
		}
		
		if ( saveResults && out != null ) 
			out.close();
		
		Runtime.getRuntime().gc();
		
		return results;
	}

	public StringBuffer searchFile(File fileName, String searchString)
	{
		StringBuffer results = new StringBuffer();
		boolean compileRetVal;
		
		compileRetVal = compile( searchString );
		Runtime.getRuntime().gc();

		try
		{
			if ( compileRetVal )
				results = grep(fileName);
			else
				results.append( "There was an error comiling your search string" );
		}
		catch (IOException x)
		{
			System.err.println(fileName.getAbsolutePath() + ": " + x);
		}

		return results;
	}
}
